package coom.zwj.reggie.utils;

public class MD5Util {

    private static final int[] SHIFT_AMOUNTS = {7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21};

    private static final int[] T = new int[64];

    static {
        for (int i = 0; i < 64; i++) {
            T[i] = (int) (Math.pow(2, 32) * Math.abs(Math.sin(i + 1)));
        }
    }

    public static String md5DigestAsHex(String input) {
        byte[] paddedBytes = padInput(input.getBytes());
        int[] state = initializeState();

        int numBlocks = paddedBytes.length / 64;

        for (int block = 0; block < numBlocks; block++) {
            int[] words = new int[16];
            for (int i = 0; i < 16; i++) {
                int index = block * 64 + i * 4;
                words[i] = (paddedBytes[index] & 0xFF) |
                        ((paddedBytes[index + 1] & 0xFF) << 8) |
                        ((paddedBytes[index + 2] & 0xFF) << 16) |
                        ((paddedBytes[index + 3] & 0xFF) << 24);
            }

            int[] prevState = new int[4];
            System.arraycopy(state, 0, prevState, 0, 4);

            for (int i = 0; i < 64; i++) {
                int f, g;
                if (i < 16) {
                    f = (prevState[1] & prevState[2]) | (~prevState[1] & prevState[3]);
                    g = i;
                } else if (i < 32) {
                    f = (prevState[3] & prevState[1]) | (~prevState[3] & prevState[2]);
                    g = (5 * i + 1) % 16;
                } else if (i < 48) {
                    f = prevState[1] ^ prevState[2] ^ prevState[3];
                    g = (3 * i + 5) % 16;
                } else {
                    f = prevState[2] ^ (prevState[1] | ~prevState[3]);
                    g = (7 * i) % 16;
                }

                int temp = prevState[3];
                prevState[3] = prevState[2];
                prevState[2] = prevState[1];
                prevState[1] += leftRotate((prevState[0] + f + words[g] + T[i]), SHIFT_AMOUNTS[i]);
                prevState[0] = temp;
            }

            for (int i = 0; i < 4; i++) {
                state[i] += prevState[i];
            }
        }

        StringBuilder hexString = new StringBuilder();
        for (int value : state) {
            hexString.append(String.format("%02x", value));
        }

        return hexString.toString();
    }

    private static int[] initializeState() {
        return new int[]{0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476};
    }

    private static byte[] padInput(byte[] input) {
        int originalLength = input.length;
        int paddingLength = 64 - ((originalLength + 8) % 64);
        int paddedLength = originalLength + paddingLength;

        byte[] paddedBytes = new byte[paddedLength];
        System.arraycopy(input, 0, paddedBytes, 0, originalLength);

        paddedBytes[originalLength] = (byte) 0x80;

        long bitLength = (long) originalLength * 8;
        for (int i = 0; i < 8; i++) {
            paddedBytes[paddedLength - 8 + i] = (byte) (bitLength >>> (i * 8));
        }

        return paddedBytes;
    }

    private static int leftRotate(int value, int amount) {
        return (value << amount) | (value >>> (32 - amount));
    }
}

























//67452301efcdab8998badcfe10325476
//df10ef8509dc176d733d59549e7dbfaf